Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.

...powered by www.netzwerkartist.de...

 <<   zurück
Visual Basic 2005 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual Basic 2005

Visual Basic 2005
1.233 S., mit 2 CDs, 59,90 Euro
Galileo Computing
ISBN 3-89842-585-1
gp Kapitel 4 Das Klassendesign (Teil 1)
  gp 4.1 Einführung in die Objektorientierung
    gp 4.1.1 Das objektorientierte Paradigma
    gp 4.1.2 Vorteile der objektorientierten Programmierung
    gp 4.1.3 Zusammenfassung
  gp 4.2 Die Klassendefinition
    gp 4.2.1 Die Deklaration von Objektvariablen
    gp 4.2.2 Zugriffsmodifizierer einer Klasse
    gp 4.2.3 Der Projekttyp »Klassenbibliothek«
    gp 4.2.4 Splitten einer Klassendefinition mit »Partial«
    gp 4.2.5 Zusammenfassung
  gp 4.3 Objektmethoden
    gp 4.3.1 Methoden mit Rückgabewert
    gp 4.3.2 Methoden ohne Rückgabewert
    gp 4.3.3 Der Aufruf einer Methode
    gp 4.3.4 Methoden mit Parameterliste
    gp 4.3.5 Rückgabewert einer Methode
    gp 4.3.6 Variablen in einer Methode
    gp 4.3.7 Zugriffsmodifizierer einer Methode
    gp 4.3.8 Referenz- und Wertparameter
    gp 4.3.9 Parameter, die Objektreferenzen erwarten
    gp 4.3.10 Methodenüberladung
    gp 4.3.11 Optionale Parameter
    gp 4.3.12 Zusammenfassung
  gp 4.4 Objekteigenschaften
    gp 4.4.1 Ergänzung der Klasse »Circle«
    gp 4.4.2 Lese- und schreibgeschützte Eigenschaften
    gp 4.4.3 Die Parameterliste einer Property-Prozedur
    gp 4.4.4 Standardeigenschaften
    gp 4.4.5 Das With ... End With-Statement
    gp 4.4.6 Konstanten mit »Const« und »ReadOnly«
    gp 4.4.7 Der Zugriff auf private Daten
    gp 4.4.8 Zusammenfassung
  gp 4.5 Konstruktoren
    gp 4.5.1 Die Konstruktoren in der Klasse »Circle«
    gp 4.5.2 Die Konstruktoraufrufe
    gp 4.5.3 Definition von Konstruktoren
    gp 4.5.4 »Friend«-Konstruktoren
    gp 4.5.5 »Private«-Konstruktoren
    gp 4.5.6 Konstruktorverkettung
    gp 4.5.7 Zusammenfassung
  gp 4.6 Der Destruktor
    gp 4.6.1 Das Zerstören von Objekten
    gp 4.6.2 Der Garbage Collector
    gp 4.6.3 Zusammenfassung
  gp 4.7 Arbeiten mit Objektreferenzen
    gp 4.7.1 Prüfen auf Initialisierung
    gp 4.7.2 Mehrere Referenzen auf ein Objekt
    gp 4.7.3 Typfeststellung einer Objektreferenz
    gp 4.7.4 Zusammenfassung


Galileo Computing

4.3 Objektmethoden  downtop

Methoden legen das Verhalten eines Objekts fest und werden innerhalb einer Klasse definiert. Methoden arbeiten oft mit den Eigenschaften des Objekts, greifen auf diese zu oder manipulieren sie. Methoden bilden das Gegenstück zu den Prozeduren und Funktionen in anderen, nicht objektorientierten Programmiersprachen.


Galileo Computing

4.3.1 Methoden mit Rückgabewert  downtop

Sehen wir uns zunächst die allgemeine Syntax einer Methode an, die einen Rückgabewert liefert:


[Modifizierer] Function Bezeichner([Parameterliste]) As Typ
' Anweisungen
[Exit Function | Return]
End Function

Die optional anzugebenden Modifizierer lassen sich in zwei Gruppen aufteilen:

gp  in die Zugriffsmodifizierer, welche die Sichtbarkeit und damit den Zugriff auf eine Methode beschreiben
gp  in allgemeine Modifikatoren, die eine weitergehende Beeinflussung der Verhaltensweise einer Methode bewirken. Diese werden Sie im weiteren Verlauf dieses Buches kennen lernen.

Methoden können als Folge ihres Aufrufs ein Ergebnis an den Aufrufer zurückliefern. Das Ergebnis ist natürlich von einem bestimmten Datentyp und muss hinter der Parameterliste angegeben werden.

Sehen wir uns das Beispiel der Klasse Circle an, in der ein Feld definiert ist, das den Radius des Kreisobjekts beschreibt. Die Klasse enthält zwei Methoden: GetFlaeche und GetUmfang.


Public Class Circle
Public Radius As Double
' ---------- Methoden ----------
Public Function GetFlaeche() As Double
Dim flaeche As Double = 3.14 * Radius ^ 2
Return flaeche
End Function
Public Function GetUmfang() As Double
Dim umfang As Double = 2 * 3.14 * Radius
Return umfang
End Function
End Class

Die Bezeichner der Methoden sind so gewählt, dass sie unzweifelhaft die Funktionalität verraten. Laut Konvention fangen Methodenbezeichner mit einem Großbuchstaben an und setzen sich nach Möglichkeit aus mehreren Begriffen zusammen, die ihrerseits zur besseren Lesbarkeit immer mit einem Großbuchstaben beginnen. Der Rückgabewert beider Methoden ist vom Typ Double, beide sind außerdem mit dem Zugriffsmodifizierer Public spezifiziert und somit uneingeschränkt sichtbar.

Methoden, die einen Wert an den Aufrufer zurückliefern, muss mitgeteilt werden, um welchen Wert es sich handelt. Hierzu dient das Schlüsselwort Return. In GetFlaeche ist das der Inhalt der lokalen Variablen flaeche, in GetUmfang der Inhalt von umfang.

Wollen Sie eine Methode mit Rückgabewert aufgrund bestimmter interner Umstände vorzeitig verlassen, rufen Sie Exit Function auf. Der Rückgabewert entspricht dem Standardwert des Rückgabedatentyps, bei einem Integer beispielsweise 0.


Galileo Computing

4.3.2 Methoden ohne Rückgabewert  downtop

Es gibt auch Methoden, die nur agieren, aber keinen Rückgabewert liefern. Deren Syntax ähnelt sehr der der Methoden mit Rückgabewert:


[Modifizierer] Sub Bezeichner([Parameterliste])
' Anweisungen
[Exit Sub | Return]
End Sub

Die Main-Methode, der Einstiegspunkt der Laufzeit einer Konsolenanwendung, ist das beste Beispiel dafür:


Sub Main()
End Sub

Dem Methodennamen folgt in runden Klammern optional eine Parameterliste, um gegebenenfalls dem Methodenaufruf Daten zu übergeben, welche die Methode zur Ausführung benötigt. Ist die Liste leer, wie auch in GetFlaeche und GetUmfang, dürfen die Klammern nicht fehlen.

Dem Methodenkopf folgt der Anweisungsblock, in dem die Funktionalität der Methode implementiert ist. Abgeschlossen wird die Methode mit End Sub. Mit Exit Sub wird die Ausführung vorzeitig abgebrochen. Das Programm verzweigt in beiden Fällen zurück in die Zeile, die dem Methodenaufruf folgt. Anstatt mit Exit Sub die Methode zu verlassen, bietet sich auch Return an.


Galileo Computing

4.3.3 Der Aufruf einer Methode  downtop

Die Klasse Circle soll nur anderen Anwendungen ihre Dienste zur Verfügung stellen und nicht eigenstartfähig sein. Deshalb wird sie in einer Klassenbibliothek codiert. Der Projektmappe fügen wir anschließend auch noch ein Projekt vom Typ Konsolenanwendung hinzu, das uns zum Testen von Circle dient. Wollen Sie das Beispiel selbst ausprobieren, dürfen Sie nicht vergessen, die Konsolenanwendung zum Startprojekt zu erklären und die Klassenbibliothek unter Verweise einzubinden. Auf der Buch-CD finden Sie das Beispiel unter Kapitel 4\CircleApplication_1. Doppelklicken Sie in diesem Ordner die Datei CircleApplication_1.sln, um die gesamte Projektmappe mit beiden Projekten in die Entwicklungsumgebung zu laden.

Von der Richtigkeit der beiden Methoden in Circle wollen wir uns natürlich auch noch überzeugen. Um die Methode GetFlaeche der Klasse Circle aufzurufen, muss Circle zuerst instanziiert werden. Anschließend legen wir den Radius des Objekts fest. GetFlaeche wird auf die Referenz des Objekts mittels Punktnotation aufgerufen und liefert einen Rückgabewert, der in der Variablen area entgegengenommen und an der Konsole ausgegeben wird.

Weil sowohl GetFlaeche als auch GetUmfang einen Wert zurückgeben, muss das Ergebnis des Methodenaufrufs nicht unbedingt in einer Variablen zwischengespeichert werden, die dem Formatausdruck der WriteLine-Methode übergeben wird. Stattdessen reicht es vollkommen aus, das Ergebnis direkt dem Methodenaufruf zu entnehmen. Dies wird anhand der Methode GetUmfang gezeigt.


Imports CircleApplication
Module Module1
Sub Main()
' Objekt vom Typ Circle erzeugen und dem Radius
' einen Wert zuweisen
Dim meinKreis As Circle = New Circle()
meinKreis.Radius = 12
' Testen der Methoden GetFlaeche
Dim area As Double = meinKreis.GetFlaeche()
Console.WriteLine("Fläche = {0}", area)
' Testen der Methode GetUmfang
Console.WriteLine("Umfang = {0}", meinKreis.GetUmfang())
Console.ReadLine()
End Sub
End Module

Vergessen Sie nicht, den Namespace CircleApplication, in dem die Klasse Circle definiert ist, mit Imports anzugeben.


Galileo Computing

4.3.4 Methoden mit Parameterliste  downtop

Methoden mit einem Parameter

Bisher haben wir nur parameterlose Methoden berücksichtigt. Viele Methoden benötigen jedoch Dateninformationen, die den Ablauf oder die Steuerung der Operation entscheidend beeinflussen. Diese Daten werden der Methode beim Aufruf als Argumente übergeben und von der Methode in der Parameterliste empfangen.

Angenommen in der Klasse Circle wäre eine Methode namens GetFlaeche definiert, die nicht auf das Feld Radius zur Flächenberechnung zurückgreift. In diesem Fall muss beim Aufruf der Methode der Radius als Argument übergeben werden. Sehen wir uns zunächst die parametrisierte Methode GetFlaeche an:


Public Function GetFlaeche(ByVal radius As Double) As Double
Dim flaeche As Double = 2 * 3.14 * radius
Return flaeche
End Function

Die Deklaration eines Parameters in der Methodendefinition erinnert an die Deklaration einer Variablen: Zuerst wird der Bezeichner des Parameters angegeben, danach folgt der Datentyp. GetFlaeche definiert also einen Parameter namens radius vom Typ Double. Zu beachten ist die Sichtbarkeit des Parameters: Er ist nur innerhalb der Methode bekannt. Damit ist seine Lebensdauer auf die Ausführungszeit der Methode beschränkt.

Nun wollen wir auch die parametrisierte Methode GetFlaeche testen:


Dim meinKreis As Circle = New Circle()
Dim kreisradius As Double = 4.5
Dim area As Double = meinKreis.GetFlaeche(kreisradius)

GetFlaeche setzt ein konkretes Objekt voraus. Deshalb muss zuerst die Klasse Circle instanziiert werden. Danach wird auf die Objektreferenz meinKreis die Methode GetFlaeche aufgerufen, wobei in den runden Klammern das Argument übergeben wird, das hier die Variable kreisradius mit dem Inhalt 4,5 ist. Die Methode nimmt das Argument im Parameter radius entgegen, der nun seinerseits ebenfalls den Inhalt 4,5 hat.

Methoden mit mehreren Parametern

In einer Parameterliste können beliebig viele Parameter definiert werden. Das folgende Codefragment beschreibt die Klasse Rectangle mit der Methode GetRectFlaeche. Die Parameterliste dieser Methode definiert die beiden Parameter laenge und breite, die durch ein Komma voneinander getrennt werden. Aus den an diese Parameter übergebenen Werten wird die Grundfläche des Rechtecks berechnet und als Resultat des Methodenaufrufs geliefert:


Class Rectangle
Public Function GetRectFlaeche(ByVal laenge As Double, _
ByVal breite As Double)
Dim flaeche As Double = laenge * breite
Return flaeche
End Function
End Class

Der Aufruf der Methode könnte folgendermaßen lauten:


Dim rechteck As Rectangle = New Rectangle()
Dim flaeche As Double = rechteck.GetRectFlaeche(3, 6)

Anstelle eines Literals können Sie auch Variablennamen angeben, die zur Laufzeit durch die entsprechenden Werte ersetzt werden:


Dim rechteck As Rectangle = New Rectangle()
Dim x As Double = 3.4
Dim y As Double = 6.19
Dim flaeche As Double = rechteck.GetRectFlaeche(x, y)

Bei Methoden, die mehr als einen Parameter erwarten, müssen Sie immer die Reihenfolge der übergebenen Argumente beachten: Das erste Argument wird dem ersten Parameter zugewiesen, das zweite Argument dem zweiten Parameter usw.


Galileo Computing

4.3.5 Rückgabewert einer Methode  downtop

Methoden mit Rückgabewert sind der einfachste Weg, um zwischen einer Methode und ihrem Aufrufer Daten auszutauschen. Dabei wird ein Methodenaufruf wie ein Variablenname bewertet, da die Methode einen bestimmten Wert repräsentiert. So wäre es möglich, einen Methodenaufruf in einem Ausdruck als Operand einzusetzen, wie das folgende Beispiel zeigt, das die Methode GetFlaeche der Circle-Klasse dazu benutzt, um das Volumen eines Zylinders zu berechnen:


Circle kreis = New Circle()
Dim hoehe As Double = 3
Dim volumen As Double = kreis.GetFlaeche(10.7) * hoehe

Einer Methode mit Rückgabewert muss gesagt werden, um welchen es sich handelt. Dazu dient das Schlüsselwort Return, hinter dem der Rückgabewert angegeben wird. Es ist nicht unbedingt notwendig, zuerst das Ergebnis einer Operation einer lokalen Variablen zuzuweisen. Die Operation darf auch direkt hinter Return erfolgen:


Public Function GetFlaeche() As Double
Return 3.14 * Math.Pow(Radius, 2)
End Function

Sobald das Return-Statement erreicht wird, kehrt die Programmausführung zum aufrufenden Code zurück. Alle Anweisungen, die einem Return folgen, werden nicht mehr ausgeführt.

Handelt es sich bei einer Methode um eine Function, muss im Anweisungsblock in jedem Fall Return enthalten und erreichbar sein, da der VB-Compiler die Kompilierung ansonsten mit einem Warnhinweis quittiert. Das wäre beispielsweise der Fall, wenn in der folgenden Methode dem Parameter die Zahl 3 übergeben wird. Der VB-Compiler ist intelligent genug, um das zu erkennen, und informiert Sie mit einem entsprechenden Hinweis.


Public Function MyMethod(ByVal x As Integer) As String
If (x < 3) Then
Return "Variable ist kleiner als 3"
ElseIf (x > 3) Then
Return "Variable ist größer als 3"
End If
End Function

Die Return-Anweisung ist nicht nur auf Methoden mit Rückgabewert beschränkt. Auch Sub-Methoden können damit vorzeitig verlassen werden. Bei diesen ist die Angabe von Return jedoch optional.

Der Rückgabewert einer Methode muss nicht unbedingt vom Aufrufer entgegengenommen werden – er kann ihn auch ignorieren. Daher ist der folgende Aufruf der Methode GetFlaeche absolut zulässig, wenn auch in diesem Fall wertlos:


kreis.GetFlaeche()

Ein Array als Rückgabewert

Wir wollen uns nun ein Beispiel ansehen, in dem der Rückgabewert einer Methode ein Array ist.


' ------------------------------------------------------------
' Beispiel:...\Kapitel 4\ArrayRueckgabe
' ------------------------------------------------------------
Module Module1
Sub Main()
Dim obj As New TestClass
Dim arr() As Int32
arr = obj.MyFunc()
For i As Integer = 0 To arr.Length – 1
Console.WriteLine(arr(i))
Next
Console.ReadLine()
End Sub
End Module
Class TestClass
Public Function MyFunc() As Int32()
Dim intArr() As Int32 = {2, 4, 6, 8}
Return intArr
End Function
End Class

Soll eine Methode ein Array an den Aufrufer zurückliefern, muss dies in der Methodensignatur bekannt gegeben werden. In MyFunc wird das lokale Array intArr mit Daten gefüllt und dient als Argument der Return-Anweisung:


Return intArr

Das ist vollkommen ausreichend, denn ein Array ist auch ein Objekt und der Name eines Arrays die Referenz auf den vom Array reservierten Speicherbereich. Der Aufrufer nimmt die Rückgabe mit


arr = obj.MyFunc()

im Array arr in Empfang. Das Array arr ist damit initialisiert. Anschließend kann in üblicher Weise über die Indizes auf die einzelnen Elemente des Arrays zugegriffen werden.


Galileo Computing

4.3.6 Variablen in einer Methode  downtop

Viele Methoden enthalten einen eigenen Satz von Variablen. Variablen, die innerhalb des Anweisungsblocks einer Methode deklariert sind, gelten als lokale Variablen. In der folgenden Methode handelt es sich um die Variable lngVariable.


Public Sub MyMethod()
Dim lngVariable As Long = 34
' Anweisungen
End Sub

Lokale Variablen sind nur in der Methode sichtbar, in der sie deklariert sind. Programmcode, der sich außerhalb der Methode befindet, kann lokale Variablen weder sehen noch manipulieren oder auswerten. Das gilt auch für Aufrufverkettungen, wenn beispielsweise aus der Methode heraus eine zweite und aus dieser heraus wieder eine dritte Methode aufgerufen wird.

Lokale Variablen sind mit ihrem typspezifischen Standardwert vorinitialisiert.

Namenskonflikte mit »Me« lösen

Felder und lokale Variablen können durchaus gleichnamig sein, wie das folgende Codefragment zeigt:


Class ClassA
Public myValue As Integer
Public Sub Method1()
Dim myValue As Integer = 10
myValue = 4711
End Sub
Public Sub Method2()
myValue = 25
End Sub
End Class

ClassA enthält das Feld myValue, derselbe Bezeichner wurde in der Methode Method1 für eine lokale Variable gewählt. Eine Anweisung in Method1 wie beispielsweise


myValue = 4711

verändert den Inhalt der Variablen, deren Gültigkeitsbereich der der Anweisung am nächsten stehende ist – in diesem Fall wird also der Inhalt der lokalen Variablen geändert und nicht das gleichnamige Feld auf Klassenebene. Soll in Method1 aber das gleichnamige, auf Klassenebene deklarierte Feld angesprochen werden, muss dem Feldnamen das Schlüsselwort Me vorausgehen, z.  B.:


Me.myValue = 245

Method2 manipuliert ebenfalls myValue. Da in Method2 die lokale Variable myValue der Methode Method1 unbekannt ist, wird der Wert direkt dem Feld zugewiesen. Es wäre aber nicht falsch, trotzdem Me zu verwenden.


Me ist ein Schlüsselwort, das auf die aktuelle Instanz verweist, und bietet sich an, um auf Methoden oder Eigenschaften des aktuellen Objekts zuzugreifen.



Galileo Computing

4.3.7 Zugriffsmodifizierer einer Methode  downtop

Zugriffsmodifizierer beschreiben die Sichtbarkeit eines Elements. Wie Sie bereits gelernt haben, kann eine Klasse nur Public oder Friend sein. In gleicher Weise werden aber auch die Sichtbarkeit und damit der Zugriff auf die Mitglieder einer Klasse festgeschrieben, zu denen unter anderem auch die Ihnen schon bekannten Felder und Methoden gehören. Den beiden bekannten Modifizierern gesellen sich noch weitere hinzu, die Sie der folgenden Tabelle entnehmen können.


Tabelle 4.2     Zugriffsmodifizierer der Klassenmitglieder

Zugriffsmodifizierer Beschreibung
Public Der Zugriff unterliegt keinerlei Einschränkungen.
Private Der Zugriff auf ein als Private definiertes Mitglied ist nur innerhalb der Klasse möglich, in der das private Member definiert ist. Alle anderen Klassen sehen private Member nicht. Deshalb ist darauf auch kein Zugriff möglich.
Protected Der Zugriff auf Protected Member ähnelt dem auf Private definierte. Die Sichtbarkeit ist in gleicher Weise eingeschränkt, jedoch werden Protected Mitglieder an abgeleitete Klassen vererbt.
Friend Die Zugriff auf Friend Member ist nur aus den Klassen heraus gestattet, die sich in derselben Assembly befinden.


Die Angabe eines Zugriffsmodifizierers ist optional. Wird darauf verzichtet, gilt das Klassenmitglied als Public deklariert.



Galileo Computing

4.3.8 Referenz- und Wertparameter  downtop

Schauen Sie sich das folgende Codefragment an:


Sub Main()
Dim intVar As Integer = 3
Console.WriteLine("intVar in Main() vorher = {0}", intVar)
TestProc(intVar)
Console.WriteLine("intVar in Main() nachher = {0}", intVar)
Console.ReadLine()
End Sub
Public Sub TestProc(ByVal intPara As Integer)
intPara = 550
Console.WriteLine("intPara in TestProc = {0}", intPara)
End Sub

In Main wird die Variable intVar deklariert und mit dem Wert 3 initialisiert. Nach der Ausgabe des Variabeleninhalts an der Konsole wird die Methode TestProc aufgerufen, der als Argument die lokale Variable intVar übergeben wird. TestProc nimmt das Argument in ihrem Parameter intPara entgegen. In der ersten Anweisung innerhalb der Methode wird der Inhalt des Parameters in 550 geändert und gleichfalls an der Konsole ausgegeben. Mit End Sub wird danach die Methode verlassen und die Kontrolle des Programmflusses wieder an Main übergeben, die ihrerseits noch einmal den Inhalt ihrer lokalen Variablen intVar an der Konsole anzeigt. Die Ausgabe wird lauten:


intVar in Main() nachher = 3

Festzuhalten bleibt, dass sich der Inhalt der in Main deklarierten Variablen intVar auch nach dem Aufruf der Methode nicht verändert hat. Der Grund für diese Tatsache – die Sie vielleicht gar nicht überrascht hat – ist in der Definition der Parameterliste zu finden. Hier steht, von uns bislang stillschweigend hingenommen, das Schlüsselwort ByVal.

In Visual Basic gibt es aber auch noch ein weiteres Schlüsselwort, bei dessen Einsatz die letzte Konsolenausgabe eine andere sein wird: ByRef. Eine Änderung der Methodensignatur in


Public Sub TestProc(ByRef intPara As Integer)

wird an der Eingabeaufforderung zu folgender Ausgabe führen:


intVar in Main() vorher = 3
intPara in TestProc = 550
intVar in Main() nachher = 550

Die Änderung der Parameterdefinition von ByVal in ByRef hat also ganz eindeutig Einfluss auf das übergebene Argument intVar ausgeübt – intVar hat nach dem Methodenaufruf genau den Inhalt angenommen, der dem Parameter intPara zugewiesen worden ist.

Um zu verstehen, was sich hinter den Kulissen abspielt, müssen wir einen Blick in den Teilbereich des Speichers werfen, in dem die Programmdaten vorgehalten werden.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 4.10     Parameterübergabe als Referenz (Call by Reference)

Zunächst wird bei der Deklaration der Variablen intVar Speicher allokiert. Nehmen wir rein hypothetisch an, es sei die Speicheradresse 10046 – so wie in der Abbildung 4.10 dargestellt ist. In diese Speicherzelle (genau genommen sind es natürlich 4 Byte, die ein Integer für sich beansprucht) wird der Wert 3 geschrieben.

Ein Parameterbezeichner ist nichts anderes als eine lokale Variable. Genau das ist der entscheidende Punkt, denn somit ist ein Parameter auch nichts anderes als der Platzhalter einer Adresse im Speicher.

Anhand des Schlüsselwortes ByRef erkennt die aufgerufene Methode TestProc, dass intPara Platzhalter für dieselbe Adresse sein soll, in der das Datum des übergebenen Arguments vorgehalten wird:

Adresse von intPara = Adresse von intVar

In unserem Beispiel beschreibt intPara folglich ebenfalls den Inhalt der Adresse 10046. Diese Speicheradresse ist damit zur Laufzeit unter zwei Namen bekannt: Unter intVar und intPara. Ändert die Methode TestProc den Inhalt von intPara in 550, wird das geänderte Datum in die Speicheradresse 10046 geschrieben.

Nachdem der Programmablauf wieder an die aufrufende Methode zurückgegeben worden ist, wird an der Konsole der Inhalt der Variablen intVar – also der Inhalt, der unter der Adresse 10046 zu finden ist – angezeigt: Es handelt sich um den Wert 550.

Zusammenfassend sei festgestellt, dass die Deklaration eines Parameters mit ByRef die Übergabe einer Speicheradresse bewirkt. Weil sowohl die aufrufende als auch die aufgerufene Methode mit derselben Adresse arbeiten, wirken sich Änderungen, die in der aufgerufenen Methode an dem Parameter vorgenommen werden, auch in der aufrufenden aus. Diese Technik der Parameterübergabe wird daher als Referenzübergabe (engl.: Call by Reference) bezeichnet.

Kommen wir noch einmal zum Eingangsbeispiel zurück. Der Parameter wurde mit dem Schlüsselwort ByVal deklariert:


Public Sub TestProc(ByVal iPara As Integer)

Wie Sie gesehen haben, wird der Inhalt des übergebenen Arguments aus Sicht der aufrufenden Methode Main nicht verändert.

Mit der Übergabe des Arguments intVar wird von der Methode TestProc zunächst Speicher allokiert – in der folgenden Abbildung 4.11 durch die fiktive Adresse 10050 beschrieben. Danach wird der Inhalt des Arguments intVar – also 3 – in die Speicherzelle 10050 kopiert.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 4.11     Parameterübergabe als Wertübergabe (Call by Value)

Ändert TestProc den Inhalt von intPara, wird die Änderung folglich in die Adresse 10050 geschrieben und nicht in die Originaladresse 10046 des übergebenen Arguments intVar. Damit weisen die beiden in unserem Beispiel angenommenen Adressen die folgenden Inhalte auf:

Adresse 10046 = 3

Adresse 10050 = 550

Nachdem der Programmablauf wieder zu der aufgerufenen Methode zurückgekehrt ist, wird der Inhalt der Variablen intVar, der sich diesmal nicht verändert hat, an der Konsole ausgegeben: Es ist weiterhin die Zahl 3. Diese Technik der Argumentübergabe wird als Wertübergabe (engl.: Call by Value) bezeichnet.

Die Wertübergabe mit ByVal ist der Standard unter Visual Basic 2005.

Vergessen Sie, entweder ByRef oder ByVal ausdrücklich anzugeben, wird die Entwicklungsumgebung die Standardbeschreibung automatisch einfügen.


Galileo Computing

4.3.9 Parameter, die Objektreferenzen erwarten  downtop

In allen bisherigen Ausführungen haben wir der Parameterliste nur einfache Datentypen wie Intger oder Long übergeben. .NET ordnet alle Datentypen zwei Gruppen zu: entweder den Werte- oder den Referenztypen. Zu den Wertetypen gehören beispielsweise Boolean, Byte, Integer, Double usw., zu den Referenztypen alle Typen, die auf einer Klassendefinition basieren. Sie werden im nächsten Kapitel noch erfahren, dass Wertetypen nicht als Klassen, sondern als Strukturen definiert sind.

Selbstverständlich können wir auch Parameter deklarieren, denen ein Referenztyp zugrunde liegt. Dazu ein Beispiel:


Module Module1
Sub Main()
Dim clsA As ClassA = New ClassA()
Dim clsB As ClassB = New ClassB()
clsB.ChangeObject(clsA)
Console.WriteLine(clsA.TestValue)
Console.ReadLine()
End Sub
End Module
Class ClassA
Public TestValue As Integer = 500
End Class
Class ClassB
Public Sub ChangeObject(ByVal obj As ClassA)
obj.TestValue = 4711
End Sub
End Class

Hier sind die beiden Klassen ClassA und ClassB definiert. ClassB hat eine Methode, der im Parameter obj ein Objekt vom Typ ClassA übergeben wird. In der Methode wird das Feld TestValue des ClassA-Objekts manipuliert.

In Main wird je ein Objekt der beiden Klassen erzeugt. Dem Aufruf der Methode ChangeObject des ClassB-Objekts wird das Objekt vom Typ ClassA übergeben. Nach dem Methodenaufruf wird an der Konsole der Inhalt des Feldes TestValue des ClassA-Objekts angezeigt – es ist der Wert 4711. Das mag im ersten Moment erstaunen, denn wir haben es in diesem Beispiel mit einem Wertparameter zu tun. Nach eingehender Überlegung wird man aber zu der Erkenntnis kommen, dass eine Objektvariable ein Verweis auf eine Speicheradresse ist, unter der das Objekt zu finden ist. Der Verweis wird in den Parameter kopiert und arbeitet dann konsequente mit dem Originalobjekt.


Galileo Computing

4.3.10 Methodenüberladung  downtop

Wir wollen nun eine Methode definieren, welche die Fläche eines Rechtecks anhand der ihr übergebenen Daten des Rechtecks ermittelt. Der Name der Funktion soll lauten GetRectangleArea. Diese Aufgabe erscheint im ersten Moment trivial, aber bei einer weitergehenden Analyse werden Sie sich die Frage stellen, wie die Daten aussehen, die von der Funktion entgegengenommen werden. Ist es das Längenmaß der beiden Seiten, also Breite und Höhe, oder sollen die beiden das Rechteck beschreibenden Eckpunkte mitgeteilt werden, aus denen die Fläche des Rechtecks berechnet wird? Insbesondere dann, wenn Sie eine Methode entwickeln, die nicht nur der eigenen Anwendung zugute kommen, sondern auch anderen Anwendungen ihre Dienste bereitstellen soll, sollten zumindest diese beiden Fälle berücksichtigt werden.

Nach dem bisherigen Kenntnisstand müssten Sie zwei Methoden mit unterschiedlichen Bezeichnern implementieren, also beispielsweise GetRectangleAreaA und GetRectagleAreaB.


'Funktion zur Übergabe des Breiten- und Höhenmaßes
Public Function GetRectangleAreaA(ByVal breite as Single, _
ByVal laenge As single) As Double
'Funktion zur Übergabe der Eckpunktkoordinaten
Public Function GetRectangleAreaB(ByVal x1 as Single, _
ByVal y1 As Single, _
ByVal x2 As single, _
ByVal y2 As Single) As Double

Dass dies keine gute Lösung ist, liegt auf der Hand. Denn das Problem, das unsere fiktive Funktion GetRectangleArea aufzeigt, nämlich für jede anders lautende Parameterliste einen anderen Methodenbezeichner festzulegen, wird bei anderen Methoden, die noch weitaus mehr voneinander abweichende Parameterlisten zulassen müssen, zu einer schier unüberschaubaren Fülle verschiedener Methodennamen führen.

Objektorientierte Sprachen bieten eine sehr einfache und effektive Problemlösung an: die Methodenüberladung. Von einer Überladung wird dann gesprochen, wenn sich zwei oder mehr gleichnamige Methoden nur in der Parameterliste unterscheiden. Die Unterscheidung anhand des Rückgabetyps ist nicht zulässig und führt zu einer Fehlermeldung.

In Visual Basic können überladene Methoden optional durch die Angabe des Schlüsselworts Overloads gekennzeichnet werden. Die Signaturen unserer Methode zur Berechnung der Rechteckfläche könnten also wie folgt definiert werden:


Public Overloads Function GetRectangleArea(ByVal breite as Single, ...) As Double

und


Public Overloads Function GetRectangleArea(ByVal x1 as Single, ...) As Double

Der Modifizierer Overloads ist optional. Sobald Sie Overloads jedoch in einer der Deklarationen verwenden, müssen Sie es in allen verwenden.

Als alleiniges Kriterium einer überladenen Methode gilt die Parameterliste. Eine Überladung liegt auch dann nicht vor, wenn – eine identische Parameterliste vorausgesetzt – eine gleichnamige Sub- und Function-Methode definiert wird.


Galileo Computing

4.3.11 Optionale Parameter  downtop

Stellen Sie sich vor, Sie beabsichtigen, eine Methode zu entwickeln, um Zahlen zu addieren. Eine Addition ist nur dann sinnvoll, wenn aus zwei Zahlen die Summe gebildet wird. Daher definieren Sie eine Funktionssignatur wie die folgende:


Public Function Add(ByVal Summand1 As Single, _
ByVal Summand2 As Single) As Single

Vielleicht haben Sie danach noch die Idee, nicht nur zwei Zahlen, sondern drei bzw. vier zu addieren. Da Sie wissen, dass Visual Basic die Methodenüberladung unterstützt, ergänzen Sie den Programmcode durch zwei entsprechend überladene Funktionen.


Public Function Add(ByVal Summand1 As Single, _
ByVal Summand2 As Single, _
ByVal Summand3 As Single) As Single

und


Public Function Add(ByVal Summand1 As Single, _
ByVal Summand2 As Single, _
ByVal Summand3 As Single, _
ByVal Summand4 As Single) As Single

Wenn Ihnen dieser Ansatz kritiklos gefällt, sollten Sie sich mit der Frage auseinander setzen, wie viele überladene Funktionen Sie maximal zu schreiben bereit sind, wenn möglicherweise nicht nur vier, sondern 10, 25 oder beliebig viele Zahlen addiert werden sollen.

Es muss für diese Problemstellung eine bessere Lösung geben – und es gibt sie auch: Sie definieren eine Parameterliste mit optionalen Parametern. Bisher haben wir alle Parameter so definiert, dass jedem Parameter beim Aufruf der Methode ein Argument übergeben werden musste. Nun lernen Sie Parameter kennen, denen ein Argument übergeben werden kann – aber nicht muss.

Um einen Parameter zu einem optionalen zu machen, muss vor dem Bezeichner das Schlüsselwort Optional angegeben werden. Dabei ist aber Folgendes zu beachten:


Regel 1

Einem optionalen Parameter darf nur ein weiterer optionaler folgen. Enthält eine Parameterliste sowohl nichtoptionale als auch optionale, stehen alle nichtoptionalen vor dem ersten optionalen.


Mit dieser Erkenntnis soll die Methode Add nun so ergänzt werden, dass nicht nur zwei, sondern maximal vier Zahlen summiert werden können. Die ersten beiden Parameter werden weiterhin in bekannter Weise statisch deklariert. Ihnen muss ein Argument übergeben werden, der dritte und vierte Parameter stehen im Bedarfsfall zur Verfügung:


Public Function Add(ByVal Summand1 As Single, _
ByVal Summand2 As Single, _
Optional ByVal Summand3 As Single = 0, _
Optional ByVal Summand4 As Single = 0) As Single

Bei der Definition optionaler Parameter in einer Parameterliste ist eine weitere wichtige Regel zu beachten:


Regel 2

Optionalen Parametern muss ein Standardwert mitgeteilt werden, der sich der Typdeklaration des Parameters anschließt.


Die Angabe eines Standardwertes erlaubt die einfache Bestimmung, ob der aufrufende Code dem optionalen Parameter ein Argument mitteilt und dieses vom deklarierten Standardwert abweicht oder nicht. Mit einer Bedingungsprüfung lässt sich das sehr einfach feststellen:


If Summand3 <> 0 Then ...

Im Beispiel zur Addition von maximal vier Zahlen kann sogar auf eine Prüfung ganz verzichtet werden. Mit


Return Summand1 + Summand2 + Summand3 + Summand4

wird in jedem Fall das korrekte Ergebnis an den Aufrufer zurückgegeben, weil aufgrund der passend gewählten Standardwerte die Summe nicht davon beeinflusst wird, ob dem dritten und/oder vierten Parameter ein Wert übergeben wird. Die so definierte Funktion Add() kann mit auf verschiedene Weisen aufgerufen werden:


sngVar = Add(Arg1, Arg2)
sngVar = Add(Arg1, Arg2, Arg3)
sngVar = Add(Arg1, Arg2, Arg3, Arg4)
sngVar = Add(Arg1, Arg2, , Arg4)

Beachten Sie insbesondere die letzte Variante. Dem dritten Parameter der Funktion wird kein Wert übergeben, dafür jedoch dem vierten. Auf die Programmlogik der Methode hat das im vorliegenden Fall keinen Einfluss, es könnte ebenso gut das vierte Argument an der dritten Position übergeben werden:


sngVar = Add(Arg1, Arg2, Arg4)

Bei anderen Methoden ist die Positionierung aber sehr wohl von entscheidender Bedeutung. Ein Parameter beschreibt häufig einen Zustand und gibt die Position in der Parameterliste vor, die beim Aufruf unbedingt eingehalten werden muss. Die Zuordnung der Position eines übergebenen Arguments zu der Position des empfangenden Parameters bleibt auch bei optionalen Parametern erhalten.

Stellen Sie sich zur Verdeutlichung eine benutzerdefinierte Methode vor, die eine beliebige algebraische Gleichung dritten Grades beschreibt:


y = Ax + Bx + Cx + D

Die vier Konstanten A, B, C und D werden durch die Parameterliste beschrieben. Um einen hohen Grad an Allgemeingültigkeit zu erreichen, werden die einzelnen Glieder der Gleichung optional deklariert und mit dem Standardwert 0 initialisiert.


Public Function GleichungGrad3(ByVal x As Integer, _
Optional ByVal A As Single = 0, _
Optional ByVal B As Single = 0, _
Optional ByVal C As Single = 0, _
Optional ByVal D As Single = 0) As Double
Return A * x ^ 3 + B * x ^ 2 + C * x + D
End Function

Um den y-Wert der Gleichung


y = 12x – 5

für x = 17 zu ermitteln, muss die Methode mit


dblY = GleichungGrad3(17, 12, , , –5)

aufgerufen werden. Beachten Sie dabei die direkte Zuordnung eines Arguments zu einem bestimmten Parameter. Das quadratische und das lineare Glied fehlen in der Definition der Gleichung. Da allerdings das Konstantenglied belegt ist und ihm die fünfte Position in der Parameterliste zugeteilt wurde, muss es auch als fünftes Argument übergeben werden. Sowohl das dritte als auch das vierte Argument bleiben ungesetzt.

Beliebig viele Übergabeparameter mit »ParamArray«

Eigentlich haben wir das ursprünglich gesetzte Ziel mit der Add-Methode erreicht, nämlich beliebig viele Dezimalzahlen vom Typ Single zu addieren: Es müssen nur entsprechend viele optionale Parameter definiert werden. Das kann im Extremfall zu einer sehr langen, unübersichtlichen Parametersignatur führen, wenn sehr viele Zahlenwerte addiert werden müssen. Ein noch größeres Handicap liegt aber wohl darin, dass – unabhängig von der Anzahl der definierten optionalen Parameter – es immer noch nicht möglich ist, wirklich eine nahezu unbegrenzte Anzahl von Werten zu addieren, denn wir sind immer noch an die Anzahl der definierten, optionalen Parameter gebunden.

Die endgültige Lösung, die uns größtmögliche Flexibilität bei gleichzeitiger Überschaubarkeit bietet, haben wir noch nicht gefunden. Visual Basic 2005 bietet uns diese jedoch auf eine sehr einfache Art und Weise an: Es wird ein Parameter als dynamisches Array mit dem Schlüsselwort ParamArray deklariert. Ein Parameter-Array erlaubt einer Methode, eine unbestimmte Anzahl von Übergabeargumenten zu akzeptieren. Die Argumente werden der Reihenfolge nach in das Parameter-Array geschrieben. Um alle übergebenen Argumente zur Laufzeit des Programms richtig zu verarbeiten, muss daher bei jedem Methodenaufruf innerhalb der Methode die Array-Größe ermittelt werden.

Im folgenden Codefragment erhält Add nun den letzten Schliff. Auf die beiden statischen Parameter wurde bewusst verzichtet, um die Signatur so einfach wie möglich zu halten. Daher muss nicht zwangsläufig beim Aufruf ein Argument übergeben werden.


Public Function GlgGrad3(ParamArray ByVal value() As Single) As Double
Dim Summe As Double
For i As Integer = 0 To Ubound(value)
Summe += value(i)
Next
Return Summe
End Function

Weil die Methode mit unterschiedlich vielen Argumenten aufgerufen werden kann, muss die Array-Obergrenze bestimmt werden. Dazu dient UBound, welcher der Name des Arrays als Argument übergeben wird, dessen Indexobergrenze ermittelt werden soll.

Mit ParamArray sind ein paar Regeln verknüpft, die eingehalten werden müssen:

gp  In der Parameterliste einer Methode darf nur ein Parameter-Array festgelegt werden.
gp  Erlaubt die Signatur einer Prozedur weitere Argumente, so ist ein Parameter-Array immer als letztes Element in der Liste zu definieren.
gp  In einer Parameterliste dürfen nicht gleichzeitig mit Optional und ParamArray deklarierte Parameter auftreten.
gp  Ein Parameter-Array muss grundsätzlich als ByVal deklariert werden und nimmt Daten gleichen Typs entgegen. Müssen dennoch typunterschiedliche Argumente übergeben werden, bietet es sich an, das Array vom Typ Object zu deklarieren. Object ist, wie später noch eingehend erörtert wird, der allgemeinste Typ und Basisklasse aller .NET-Typen.
gp  Ein Parameter-Array ist immer eindimensional.

Galileo Computing

4.3.12 Zusammenfassung  toptop

gp  Es wird zwischen Methoden mit Rückgabewert (Function) und Methoden ohne Rückgabewert (Sub) unterschieden.
gp  Methoden können überladen werden. Ausschlaggebend dafür ist einzig und allein nur die Parameterliste. Überladene Methoden können mit dem Modifizierer Overloads gekennzeichnet werden.
gp  Liefert eine Methode dem Aufrufer ein Resultat, wird dieses mit der Anweisung Return bereitgestellt. Nach der Ausführung von Return wird die Kontrolle des Programmablaufs an den Aufrufer zurückgegeben, auch bei Sub-Methoden.
gp  Lokale Variablen sind Variablen, die innerhalb einer Methode deklariert und nur in dieser bekannt sind.
gp  Parameter sind entweder Wert- oder Referenzparameter (ByVal bzw. ByRef).
gp  Parameter, die ByVal übergeben werden, können ohne Auswirkung auf die aufrufende Methode in der aufgerufenen manipuliert werden. Diese Übergabemethode wird als Call by Value bezeichnet. Parameter, die ByRef definiert sind, empfangen die Adresse des Arguments, nicht aber direkt dessen Datum. Ändert die aufgerufene Methode einen ByRef empfangenen Parameter, wirkt sich dies auf den Aufrufer aus. Diese Art der Parameterdefinition wird als Call by Reference bezeichnet.
gp  Die Übergabe von Objektreferenzen erfolgt grundsätzlich immer ByRef, selbst dann, wenn der Typ eines solchen Parameters ByVal definiert ist.
gp  Argumente können optional übergeben werden. Dazu wird der Parameter mit dem Schlüsselwort Optional definiert. Bei diesen Parametern ist grundsätzlich ein Standardwert anzugeben, den der Parameter annimmt, falls der Aufrufer an der Position des optionalen Parameters kein Argument übergibt.
gp  Hinter Optional-Parametern dürfen nur weitere optionale folgen.
gp  Um eine unbegrenzte Anzahl optionaler Parameter bereitzustellen, bietet sich die Definition mit ParamArray an. ParamArray-Parameter dürfen nicht zusammen mit optionalen Parametern eingesetzt werden und stehen immer als letztes Glied in der Parameterliste.
 <<   zurück
  
  Zum Katalog
Zum Katalog: Visual Basic 2005
Visual Basic 2005
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Visual C# 2005






 Visual C# 2005


Zum Katalog: Fortgeschrittene Programmierung mit Visual C# 2005






 Fortgeschrittene
 Programmierung
 mit Visual C# 2005


Zum Katalog: Das Programmierhandbuch SQL Server 2005






 Das Programmier-
 handbuch
 SQL Server 2005


Zum Katalog: Einstieg in Visual Basic 2005






 Einstieg in
 Visual Basic 2005


Zum Katalog: Einstieg in Visual C# 2005






 Einstieg in
 Visual C# 2005


Zum Katalog: Konzepte und Lösungen für Microsoft-Netzwerke






 Konzepte und
 Lösungen für
 Microsoft-Netzwerke


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo








Copyright © Galileo Press 2007
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de